﻿
using System ;
using System.Collections.Generic ;

using MskEdit.Msk.Representation ;


namespace MskEdit.Msk.Model
{
    public class MskDocument {

        #region Private data

        private string                      docName_ ;
        private string[]                    allLines_ ;
        private HashSet<MskPageKey>         pageKeys_ ;
        private MskLineDictionary           lineDict_ ; // Line key to line number


        static private HashSet<MskPageKey> GetPageKeysFrom( string[] allLines ) {
        
            HashSet<MskPageKey> pageKeys = new HashSet<MskPageKey>() ;
            
            foreach ( var line in allLines ) {
            
                MskPageKey maybePageKey = MskPageKey.TryFrom( line, null ) ;
                
                if ( maybePageKey == null )
                    continue ;
                MskPageKey pageKey = maybePageKey ;
                
                pageKeys.Add( pageKey ) ;
            }
            
            return  pageKeys ;            
        }

        #endregion
        
        #region Public events
        
        public delegate void LineChangedEventHandler( MskLine mskLine ) ;
        public event LineChangedEventHandler LineChanged ;

        #endregion

        #region Public foundation

        public MskDocument( String docName, string[] allLines ) {
            docName_  = docName ;            
            allLines_ = allLines ;
            pageKeys_ = GetPageKeysFrom( allLines ) ;
            lineDict_ = MskLineDictionary.From( allLines ) ;
        }

        #endregion

        #region Public methods

        public MskPage getPageWith( MskPageKey pageKey ) {
            return new MskPage( pageKey, allLines_ ) ;
        }


        public MskLine getAnyLineWith( MskLineKey anyMskLineKey, MskLine fallbackValue ) {
        
            if ( anyMskLineKey == null )
                return fallbackValue ;
                
            string lineKeyAsString = anyMskLineKey.ToString() ;
        
            if ( ! lineDict_.ContainsKey( lineKeyAsString ) )
                return fallbackValue ;
            
            int i       = lineDict_[ lineKeyAsString ] ;
            string line = allLines_[i] ;
            
            MskLine mskLine = MskLine.TryFrom( line, null ) ;
            if ( mskLine == null )
                return fallbackValue ;
            
            return mskLine ;
        }
        
        
        public void updateContentWith( MskLine mskLine ) {
        
            bool   isUpdated            = false ;
            string mskLineKeyAsString   = mskLine.LineKey.ToString() ;
            
            if ( lineDict_.ContainsKey( mskLineKeyAsString ) ) {
                int i = lineDict_[ mskLineKeyAsString ] ;
                string oldString = allLines_[i] ;
                string newString = mskLine.ToString() ;
                
                if ( ! newString.Equals( oldString ) ) {
                    allLines_[i] = newString ;
                    isUpdated = true ;
                }
            }
            else {
                int l = allLines_.Length ;
                string[] newAllLines = new string[l+1] ;

                allLines_.CopyTo( newAllLines, 0 ) ;
                newAllLines[l] = mskLine.ToString() ;
                
                allLines_ = newAllLines ;
                lineDict_[ mskLineKeyAsString ] = l ;
                
                isUpdated = true ;
            }
            
            if ( isUpdated && LineChanged != null ) 
                LineChanged.Invoke( mskLine ) ;
        }

        #endregion

        #region Public properties

        public string DocumentName {
            get { return docName_ ; }
        }


        public HashSet<MskPageKey> PageKeys {
            get { return pageKeys_ ; }    
        }


        public string[] AllLines {
            get { return allLines_ ; }    
        }

#endregion

    }
}
